local lang_utils = require("mvc.utils.lang_utils");
local req_utils = require("mvc.utils.req_utils");
local InterceptorHandler = require("mvc.interceptor_handler");
local view_engine = require("mvc.view.view_engine");
local const = require("mvc.config.const");
local hades = require("config.hades");
local resp = require("mvc.resp");
local req = require("mvc.req");
local eh = require("mvc.exception_handler");


local dispatcher = {
	router = nil,  --router配置
	uri = nil,     --URI
	method = nil   --Action方法名称
};


--[[
	实例化一个Dispathcer
	@router uri路由配置
	@uri 请求路径
]]
function dispatcher:new(router, uri)
	local o = {};
	setmetatable(o, self);
	self.__index = self;
	self.router = router;
	self.uri = uri;
	self.method = req_utils.get_method(uri);
	return o;
end


--[[
	根据uri router进行action方法反射调用
	方法调用顺序： 拦截器do_before -> Action方法 -> 拦截器do_after
	调用Action方法如果为一个string值，则进行模板渲染
	调用Action方法如果为一个table值，则输出来json
]]
function dispatcher:do_dispatch()

	if (self.uri == '' or self.uri == "/") then
		resp.redirect("/index.html");
		return;
	end

	local rr = {req, resp};

	local interceptor_handler = InterceptorHandler:new(self.uri);
	self:_init_wildcard();
	
	self:do_interceptor_before(interceptor_handler);
	local action_inst = require(self.router.action);
	local method = self.method;
	local action_result, template_context, exception = lang_utils.reflect_1(action_inst, method, rr);
	
	if (action_result == false) then
		eh.to_error("No package {1} or method {2} found", {self.router.action, method}, exception)
		return;
	end
	
	if (method == nil) then
		eh.to_error("Action {1} no method found {2}", {self.router.action, method}, exception);
		return;
	end
	
	--处理json
	if (action_result ~= nil and type(action_result) == "table") then
		resp.out_json(action_result);
		return;
	end
	
	--action_result类型只能为string或table或nil
	if action_result ~= nil and type(action_result) ~= "string" then
		eh.to_error("Action {1}.{2} method can only return table or string or nil", {self.router.action, method}, exception);
		return;
	end
	
	--处理action返回值为string
	if type(action_result) == "string" then
		local path = nil;

		--先获取全局result配置
		path = hades.global_results[action_result];
		if path == nil then
			--全局result未定义时获取action_result对应的模板路径或uri路径
			path = self.router[const.RES][self.method][action_result];
		end
		
		--判断path是否是重定向
		local redirect = self:_is_redirect(path);
		if (redirect ~= nil) then
			resp.redirect(redirect);
			return;
		end
		
		--非重定向,处理模板渲染逻辑
		if path == nil or #path < 1 then
			eh.to_error("Return name：{1} 's template path is null or empty", {action_result});
		end
		
		local render_result = view_engine.do_render(path, template_context);
		--resp.out_json(template_context);
		resp.set_content_type("text/html;charset=UTF-8").out(render_result);
	end
	
	--返回为nil的情况方法调用时就处理了

	self:do_interceptor_after(interceptor_handler);
	
end

--[[
	执行拦截器do_before方法链
]]
function dispatcher:do_interceptor_before(interceptor_handler)
	interceptor_handler:do_before();
end

--[[
	执行拦截器do_after方法链
]]
function dispatcher:do_interceptor_after(interceptor_handler)
	interceptor_handler:do_after();
end

--[[
	Action配置通配符处理
]]
function dispatcher:_init_wildcard()
	local t = self.router[const.RES][const.WID];
	if (t ~= nil and type(t) == "table") then
		self.router[const.RES][self.method] = {};
		local r = self.router[const.RES][self.method];
		r[const.SUC] = string.gsub(t[const.SUC], const.LOR, self.method);
	end
end

--[[
	判断是否为redirect
]]
function dispatcher:_is_redirect(action_result)
	local a = string.find(action_result, const.RED);
	if a ~= nil and a > 0 then
		local b = string.sub(action_result, a - 1, #action_result);
		return b;
	end
	return nil;
end

return dispatcher;

